package com.zdw.demo.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.google.common.collect.Lists;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import com.zdw.common.constant.common.CommonConstants;
import com.zdw.common.exception.GlobalException;
import com.zdw.common.parent.JSONResult;
import com.zdw.demo.config.international.InternationalUtils;
import com.zdw.demo.config.pay.WechatConfig;
import com.zdw.demo.dto.WechatCallBackParam;
import com.zdw.demo.dto.WechatCreateOrder;
import com.zdw.demo.dto.WechatRefund;
import com.zdw.demo.dto.WechatRefundParam;
import com.zdw.demo.entity.PcPubCallbackUrl;
import com.zdw.demo.entity.WechatOrder;
import com.zdw.demo.entity.WechatOrderLog;
import com.zdw.demo.entity.WechatRefundHistory;
import com.zdw.demo.service.*;
import com.zdw.demo.vo.WechatCallbackResult;
import com.zdw.demo.vo.WechatPayCallback;
import com.zdw.demo.vo.WechatQueryOrder;
import com.zdw.demo.vo.WechatRefundResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
import java.util.stream.Stream;


/**
 * Service : 微信支付 服务类
 * 用于处理实际的业务逻辑。
 */
@Service
@Slf4j
public class WechatPayServiceImpl implements WechatPayService {

    // 微信支付配置信息
    @Autowired
    private WechatConfig wechatConfig;

    // 微信订单服务类
    @Autowired
    private WechatOrderService orderService;

    // 微信订单日志服务
    @Autowired
    private WechatOrderLogService orderLogService;

    // 微信退款订单服务
    @Autowired
    private WechatRefundHistoryService refundHistoryService;

    //回调地址Mapper
    @Autowired
    private PcPubCallbackUrlService urlService;

    // 微信支付请求对象
    private CloseableHttpClient wechatPayClient;

    // 微信验签对象
    private AutoUpdateCertificatesVerifier verifier;

    /**
     * 读取请求数据流
     *
     * @param request
     * @return
     */
    private String getRequestBody(HttpServletRequest request) {
        StringBuffer sb = new StringBuffer();
        try (ServletInputStream inputStream = request.getInputStream();
             BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        ) {
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            log.error("读取微信支付回调数据异常:{}", e);
        }
        return sb.toString();
    }

    /**
     * 验证签名
     *
     * @param serialNo  微信平台-证书序列号
     * @param signStr   自己组装的签名串
     * @param signature 微信返回的签名
     * @return
     * @throws UnsupportedEncodingException
     */
    private boolean verifiedSign(String serialNo, String signStr, String signature) {
        try {
            byte[] bytes = signStr.getBytes("utf-8");
            return verifier.verify(serialNo, bytes, signature);
        } catch (UnsupportedEncodingException e) {
            throw new GlobalException(InternationalUtils.getInternational("wechat.pay.verifierFail"), e.getMessage());
        }
    }

    /**
     * 解密body的密文
     *
     * @param body
     * @return
     * @throws UnsupportedEncodingException
     * @throws GeneralSecurityException
     */
    private String decryptBody(String body) throws UnsupportedEncodingException, GeneralSecurityException {
        AesUtil    aesUtil        = new AesUtil(wechatConfig.getApiV3Key().getBytes("utf-8"));
        JSONObject object         = JSONUtil.parseObj(body);
        JSONObject resource       = object.getJSONObject("resource");
        String     ciphertext     = resource.getStr("ciphertext");
        String     associatedData = resource.getStr("associated_data");
        String     nonce          = resource.getStr("nonce");
        return aesUtil.decryptToString(associatedData.getBytes("utf-8"), nonce.getBytes("utf-8"), ciphertext);
    }

    /**
     * 获取证书私钥
     *
     * @param filename 私钥文件路径  (required)
     * @return 私钥对象
     */
    private PrivateKey getPrivateKey(String filename) {
        String content;
        try {
            content = new String(Files.readAllBytes(Paths.get(wechatConfig.getResourceUrl(), filename)), "utf-8");
        } catch (IOException e) {
            throw new GlobalException(InternationalUtils.getInternational("wechat.pay.certificateLoadFail"), e.getMessage());
        }
        try {
            String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
                    .replace("-----END PRIVATE KEY-----", "")
                    .replaceAll("\\s+", "");

            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePrivate(
                    new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
        } catch (NoSuchAlgorithmException e) {
            throw new GlobalException(InternationalUtils.getInternational("wechat.pay.rsaFail"), e.getMessage());
        } catch (InvalidKeySpecException e) {
            throw new GlobalException(InternationalUtils.getInternational("wechat.pay.invalidKey"));
        }
    }

    /**
     * 初始化微信支付的wechatPayClient
     *
     * @throws IOException
     */
    private void setup() {
        // 加载商户私钥（privateKey：私钥字符串）
        PrivateKey merchantPrivateKey = getPrivateKey("apiclient_key.pem");

        // 加载平台证书（mchId：商户号,mchSerialNo：商户证书序列号,apiV3Key：V3密钥）
        AutoUpdateCertificatesVerifier verifier = null;
        try {
            verifier = new AutoUpdateCertificatesVerifier(
                    new WechatPay2Credentials(
                            wechatConfig.getMchId(),
                            new PrivateKeySigner(wechatConfig.getCertCode(), merchantPrivateKey)
                    ),
                    wechatConfig.getApiV3Key().getBytes("utf-8")
            );
        } catch (UnsupportedEncodingException e) {
            throw new GlobalException(InternationalUtils.getInternational("wechat.pay.certificateLoadFail"));
        }

        // 初始化wechatPayClient
        wechatPayClient = WechatPayHttpClientBuilder.create()
                .withMerchant(wechatConfig.getMchId(), wechatConfig.getCertCode(), merchantPrivateKey)
                .withValidator(new WechatPay2Validator(verifier)).build();
    }

    /**
     * 初始化微信支付的配置AutoUpdateCertificatesVerifier
     *
     * @throws IOException
     */
    public void setupForVerifier() {
        // 加载商户私钥（privateKey：私钥字符串）
        PrivateKey merchantPrivateKey = getPrivateKey("apiclient_key.pem");

        // 加载平台证书（mchId：商户号,mchSerialNo：商户证书序列号,apiV3Key：V3密钥）
        try {
            verifier = new AutoUpdateCertificatesVerifier(
                    new WechatPay2Credentials(
                            wechatConfig.getMchId(),
                            new PrivateKeySigner(wechatConfig.getCertCode(), merchantPrivateKey)
                    ),
                    wechatConfig.getApiV3Key().getBytes("utf-8")
            );
        } catch (UnsupportedEncodingException e) {
            throw new GlobalException(InternationalUtils.getInternational("wechat.pay.verifierFail"));
        }
    }

    /**
     * 创建订单对象
     *
     * @return
     */
    private WechatOrder createOrder(String outTradeNo, String description, double total, String codeUrl, String appName, String expireTime) {
        WechatOrder order = new WechatOrder();
        Date        date  = new Date();
        order.setOut_trade_no(outTradeNo);
        order.setTrade_type(CommonConstants.WECHAT_TRADE_TYPE_NATIVE);
        order.setTrade_state(CommonConstants.WECHAT_TRADE_STATE_NOTPAY);
        order.setTrade_state_desc(CommonConstants.WECHAT_TRADE_STATE_NOTPAY_DESC);
        order.setTotal(total);
        order.setDescription(description);
        order.setCode_url(codeUrl);
        order.setApp_flag(appName);
        order.setTime_expire(expireTime);
        order.setIs_notify(0);
        //order.setCreate_user_id();
        //order.setCreate_user_name();
        order.setCreate_time(date);
        //order.setUpdate_user_id();
        //order.setUpdate_user_name();
        order.setUpdate_time(date);
        return order;
    }

    /**
     * 更新订单对象
     *
     * @return
     */
    private WechatOrder updateOrder(WechatQueryOrder wechatQueryOrder) {
        WechatOrder order = new WechatOrder();
        Date        date  = new Date();
        order.setOut_trade_no(wechatQueryOrder.getOut_trade_no());
        order.setTransaction_id(wechatQueryOrder.getTransaction_id());
        order.setTrade_type(wechatQueryOrder.getTrade_type());
        order.setTrade_state(wechatQueryOrder.getTrade_state());
        order.setTrade_state_desc(wechatQueryOrder.getTrade_state_desc());
        order.setBank_type(wechatQueryOrder.getBank_type());
        order.setAttach(wechatQueryOrder.getAttach());
        order.setSuccess_time(wechatQueryOrder.getSuccess_time());
        order.setOpenid(ObjectUtil.isNotEmpty(wechatQueryOrder.getPayer()) ? wechatQueryOrder.getPayer().getOpenid() : null);
        if (ObjectUtil.isNotEmpty(wechatQueryOrder.getAmount())) {
            order.setTotal(wechatQueryOrder.getAmount().getTotal());
        }
        order.setUpdate_time(date);
        return order;
    }

    private WechatOrder getOrderFromCallback(WechatCallBackParam callBackParam) {
        WechatOrder order = new WechatOrder();
        Date        date  = new Date();
        order.setOut_trade_no(callBackParam.getOut_trade_no());
        order.setTransaction_id(callBackParam.getTransaction_id());
        order.setTrade_type(callBackParam.getTrade_type());
        order.setTrade_state(callBackParam.getTrade_state());
        order.setTrade_state_desc(callBackParam.getTrade_state_desc());
        order.setBank_type(callBackParam.getBank_type());
        order.setAttach(callBackParam.getAttach());
        order.setSuccess_time(callBackParam.getSuccess_time());
        order.setOpenid(ObjectUtil.isNotEmpty(callBackParam.getPayer()) ? callBackParam.getPayer().getOpenid() : null);
        if (ObjectUtil.isNotEmpty(callBackParam.getCallBackAmount())) {
            order.setTotal(callBackParam.getCallBackAmount().getTotal());
        }
        order.setUpdate_time(date);
        return order;
    }

    private WechatQueryOrder getWechatQueryOrderFromOrder(WechatOrder wechatOrder) {
        WechatQueryOrder wechatQueryOrder = new WechatQueryOrder(wechatOrder.getOpenid(), wechatOrder.getTotal());
        wechatQueryOrder.setOut_trade_no(wechatOrder.getOut_trade_no());
        wechatQueryOrder.setTransaction_id(wechatOrder.getTransaction_id());
        wechatQueryOrder.setTrade_type(wechatOrder.getTrade_type());
        wechatQueryOrder.setTrade_state(wechatOrder.getTrade_state());
        wechatQueryOrder.setTrade_state_desc(wechatOrder.getTrade_state_desc());
        wechatQueryOrder.setBank_type(wechatOrder.getBank_type());
        wechatQueryOrder.setAttach(wechatOrder.getAttach());
        wechatQueryOrder.setSuccess_time(wechatOrder.getSuccess_time());
        return wechatQueryOrder;
    }

    private WechatRefundHistory getWechatRefundHistory(WechatRefundResult wechatRefundResult) {
        return new WechatRefundHistory(
                wechatRefundResult.getRefund_id(),
                wechatRefundResult.getOut_refund_no(),
                wechatRefundResult.getTransaction_id(),
                wechatRefundResult.getOut_trade_no(),
                wechatRefundResult.getAmount().getRefund(),
                wechatRefundResult.getAmount().getTotal(),
                wechatRefundResult.getRefund_status(),
                new Date()
        );
    }

    /**
     * 1:获取支付二维码(创建订单)
     *
     * @param outTradeNo  内部订单号
     * @param description 商品描述
     * @param total       总金额(单位:元)
     * @param appName     APP回调标识
     * @return
     * @throws IOException
     */
    public JSONResult createOrder(String outTradeNo, String description, double total, String appName) {
        JSONResult  js = new JSONResult();
        WechatOrder order;

        // 判断当前内部单号是否发起过支付, 如果已发起过需要卡住
        WechatOrder wechatOrder = orderService.selectByOutTradeNo(outTradeNo);
        if (ObjectUtil.isNotEmpty(wechatOrder) && StrUtil.isNotEmpty(wechatOrder.getOut_trade_no())) {
            js.setStatus(500);
            js.setSuccess(false);
            js.setMsg(InternationalUtils.getInternational("wechat.pay.exist"));
            js.setData(StrUtil.EMPTY);
            return js;
        }

        // 判断是否初始化wechatPayClient
        if (wechatPayClient == null) {
            setup();
        }
        // 封装请求参数
        WechatCreateOrder wechatCreateOrder = new WechatCreateOrder(wechatConfig.getAppId(), wechatConfig.getMchId(), description, outTradeNo, wechatConfig.getWechatNotifyUrl(), total * 100);
        // 设置订单失效时间(默认15分钟,可以在配置文件中的wechat.expireMinutes属性进行设置)
        String expireTime = getExpireTime();
        wechatCreateOrder.setTime_expire(expireTime);
        // 转成JSON
        String       reqData = JSONUtil.toJsonStr(wechatCreateOrder);
        StringEntity entity  = new StringEntity(reqData, "utf-8");
        entity.setContentType("application/json");
        // 封装请求参数、完成签名并执行请求
        HttpPost httpPost = new HttpPost(CommonConstants.WECHAT_CODE_URL);
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");
        CloseableHttpResponse response = null;
        try {
            response = wechatPayClient.execute(httpPost);
            // 解析返回结果
            int statusCode = response.getStatusLine().getStatusCode();
            js.setStatus(statusCode);
            HttpEntity responseEntity = response.getEntity();
            String     responseBody   = null;
            try {
                responseBody = EntityUtils.toString(responseEntity, "UTF-8");
            } catch (IOException e) {
                throw new GlobalException(InternationalUtils.getInternational("wechat.pay.dataParseFail"), e.getMessage());
            }
            JSONObject jsonObject = JSONUtil.parseObj(responseBody);
            if (statusCode == HttpStatus.OK.value()) {
                //处理成功
                log.info("获取二维码接口调用成功,返回数据 = {}", responseBody);
                String codeUrl = jsonObject.getStr("code_url");
                js.setSuccess(true);
                js.setMsg("SUCCESS");
                js.setData(codeUrl);
                //保存/更新订单信息
                order = createOrder(outTradeNo, description, total, codeUrl, appName, expireTime);
                orderService.saveOrUpdate(order);
                //添加微信支付的日志
                WechatOrderLog wechatOrderLog = new WechatOrderLog(outTradeNo, codeUrl, total, description, appName, new Date());
                orderLogService.save(wechatOrderLog);
            } else {
                //处理失败
                log.info("获取二维码接口调用失败,返回状态码 = {},返回信息 = {}", statusCode, responseBody);
                String message = jsonObject.getStr("message");
                js.setSuccess(false);
                js.setMsg(message);
                js.setData(StrUtil.EMPTY);
            }
        } catch (IOException e) {
            throw new GlobalException(InternationalUtils.getInternational("wechat.pay.dataParseFail"), e.getMessage());
        } finally {
            try {
                Objects.requireNonNull(response).close();
            } catch (IOException e) {
                throw new GlobalException(InternationalUtils.getInternational("common.stream.close"), e.getMessage());
            }
        }
        return js;
    }

    /**
     * 2:支付回调(未使用、未测试、需要Https)
     * <p>
     * 注意：
     * • 同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。 推荐的做法是，当商户系统收到通知进行处理时，先检查对应业务数据的状态，并判断该通知是否已经处理。如果未处理，则再进行处理；如果已处理，则直接返回结果成功。在对业务数据进行状态检查和处理之前，要采用数据锁进行并发控制，以避免函数重入造成的数据混乱。
     * • 如果在所有通知频率后没有收到微信侧回调，商户应调用查询订单接口确认订单状态。
     * • 特别提醒：商户系统对于开启结果通知的内容一定要做签名验证，并校验通知的信息是否与商户侧的信息一致，防止数据泄露导致出现“假通知”，造成资金损失。
     */
    public WechatCallbackResult callback(HttpServletRequest request, HttpServletResponse response) {
        // 判断是否初始化验签配置
        if (verifier == null) {
            setupForVerifier();
        }
        // 获取报文及相关请求头信息
        String body = getRequestBody(request);
        log.info("收到微信支付回调,返回数据：{}", body);
        String nonceStr  = request.getHeader("Wechatpay-Nonce");
        String signature = request.getHeader("Wechatpay-Signature");
        String serialNo  = request.getHeader("Wechatpay-Serial");
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        //构造签名串
        String               signStr              = Stream.of(timestamp, nonceStr, body).collect(Collectors.joining("\n", "", "\n"));
        WechatCallbackResult wechatCallbackResult = new WechatCallbackResult(CommonConstants.RESULT_SUCCESS, CommonConstants.RESULT_SUCCESS_MSG);
        try {
            //验证签名是否通过
            boolean result = verifiedSign(serialNo, signStr, signature);
            if (result) {
                //解密数据
                String plainBody = decryptBody(body);
                log.info("解密后的明文:{}", plainBody);

                // 将 JSON 字符串转换为 Java 对象
                WechatOrder         order;
                WechatCallBackParam callBackParam = JSONUtil.toBean(plainBody, WechatCallBackParam.class);
                log.info("最终得到回调数据:{}", callBackParam);
                order = getOrderFromCallback(callBackParam);
                if (ObjectUtil.isNotEmpty(callBackParam) && StrUtil.equals(callBackParam.getTrade_state(), CommonConstants.WECHAT_TRADE_STATE_SUCCESS)) {
                    String payResultNotifyUrl = urlService.selectByOutTradeNo(callBackParam.getOut_trade_no());
                    if (StrUtil.isNotEmpty(payResultNotifyUrl)) {
                        order.setPay_result_notify_url(payResultNotifyUrl);
                        boolean isSuccess = callbackToApp(HttpClient.newHttpClient(), order);
                        order.setIs_notify(isSuccess ? 1 : 0);
                    } else {
                        log.error("通知URL不存在,无法进行回调,内部订单号:{},微信支付单号:{}", callBackParam.getOut_trade_no(), callBackParam.getTransaction_id());
                    }
                }
                // 更新订单信息
                orderService.updateByOutTradeNo(order);
            }
        } catch (Exception e) {
            log.error("微信支付回调异常:{}", e);
            wechatCallbackResult = new WechatCallbackResult(CommonConstants.RESULT_FAIL, CommonConstants.RESULT_FAIL_MSG);
        }
        return wechatCallbackResult;
    }

    /**
     * 3:微信支付订单查询
     * <p>
     * - 需要调用查询接口的情况：
     * • 当商户后台、网络、服务器等出现异常，商户系统最终未接收到支付通知。
     * • 调用支付接口后，返回系统错误或未知交易状态情况。
     * • 调用付款码支付API，返回USERPAYING的状态。
     * • 调用关单或撤销接口API之前，需确认支付状态。
     *
     * @param transactionId 微信支付订单号
     */
    public JSONResult queryOrderByWechat(String transactionId) {
        WechatOrder      order;
        JSONResult       js               = new JSONResult();
        WechatQueryOrder wechatQueryOrder = new WechatQueryOrder();

        // 查询并判断是否已支付成功,支付成功直接返回,不再去查微信端
        WechatOrder wechatOrder = orderService.selectByTransactionId(transactionId);
        if (ObjectUtil.isNotEmpty(wechatOrder)
                && (StrUtil.equals(wechatOrder.getTrade_state(), CommonConstants.WECHAT_TRADE_STATE_SUCCESS)
                || StrUtil.equals(wechatOrder.getTrade_state(), CommonConstants.WECHAT_TRADE_STATE_CLOSED)
                || StrUtil.equals(wechatOrder.getTrade_state(), CommonConstants.WECHAT_TRADE_STATE_EXPIRE))
        ) {
            js.markSuccess("SUCCESS", getWechatQueryOrderFromOrder(wechatOrder));
            return js;
        }
        // 判断是否初始化wechatPayClient
        if (wechatPayClient == null) {
            setup();
        }
        // 创建 HttpClient 对象
        CloseableHttpResponse response = null;
        try {
            // 创建 HttpGet 请求
            URL     url     = new URL(CommonConstants.WECHAT_QUERY_ORDER_URL.replace("{transaction_id}", transactionId) + "?mchid=" + wechatConfig.getMchId());
            HttpGet httpGet = new HttpGet(url.toURI());
            httpGet.setHeader("Accept", "application/json");
            response = wechatPayClient.execute(httpGet);
            // 解析返回结果
            int statusCode = response.getStatusLine().getStatusCode();
            js.setStatus(statusCode);
            HttpEntity entity       = response.getEntity();
            String     responseBody = EntityUtils.toString(entity);
            if (statusCode == HttpStatus.OK.value()) {
                log.info("微信支付订单查询接口调用成功,返回数据{}", responseBody);
                // 将 JSON 字符串转换为 Java 对象
                wechatQueryOrder = JSONUtil.toBean(responseBody, WechatQueryOrder.class);
                // 金额需要从分转为元
                if (ObjectUtil.isNotEmpty(wechatQueryOrder.getAmount())) {
                    wechatQueryOrder.getAmount().setTotal(wechatQueryOrder.getAmount().getTotal() / 100);
                }
                js.setSuccess(true);
                js.setMsg("SUCCESS");
                js.setData(wechatQueryOrder);
                // 支付完成时,回调到应用系统
                order = updateOrder(wechatQueryOrder);
                WechatOrder paymentOrder = JSONUtil.toBean(responseBody, WechatOrder.class);
                if (ObjectUtil.isNotEmpty(paymentOrder) && StrUtil.equals(paymentOrder.getTrade_state(), CommonConstants.WECHAT_TRADE_STATE_SUCCESS)) {
                    PcPubCallbackUrl callbackUrl = urlService.selectByQuery(paymentOrder.getApp_flag());
                    if (ObjectUtil.isNotEmpty(callbackUrl) && StrUtil.isNotEmpty(callbackUrl.getPayResultNotifyUrl())) {
                        paymentOrder.setPay_result_notify_url(callbackUrl.getPayResultNotifyUrl());
                        boolean isSuccess = callbackToApp(HttpClient.newHttpClient(), paymentOrder);
                        order.setIs_notify(isSuccess ? 1 : 0);
                    } else {
                        log.error("通知URL不存在,无法进行回调,微信支付单号:{}", transactionId);
                    }
                }
                // 如果是待支付的订单,且已超过失效时间,将订单状态改为已关闭(微信不会更新订单为已关闭,需要自己处理,真恶心啊)
                if (StrUtil.equals(wechatQueryOrder.getTrade_state(), CommonConstants.WECHAT_TRADE_STATE_NOTPAY)) {
                    DateTimeFormatter formatter   = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX");
                    LocalDateTime     currentTime = new Date().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                    LocalDateTime     expireTime  = LocalDateTime.parse(wechatOrder.getTime_expire(), formatter);
                    if (ObjectUtil.isNotEmpty(wechatOrder) && currentTime.isAfter(expireTime)) {
                        order.setTrade_state(CommonConstants.WECHAT_TRADE_STATE_EXPIRE);
                        order.setTrade_state_desc(CommonConstants.WECHAT_TRADE_STATE_EXPIRE_DESC);
                        order.setMessage(InternationalUtils.getInternational("wechat.pay.autoClose"));
                        wechatQueryOrder.setTrade_state(CommonConstants.WECHAT_TRADE_STATE_EXPIRE);
                        wechatQueryOrder.setTrade_state_desc(CommonConstants.WECHAT_TRADE_STATE_EXPIRE_DESC);
                    }
                }
                // 更新订单信息
                orderService.updateByOutTradeNo(order);
            } else {
                log.info("微信支付订单查询接口调用失败,返回状态码 = {},返回信息 = {}", statusCode, responseBody);
                JSONObject jsonObject = JSONUtil.parseObj(responseBody);
                js.setSuccess(false);
                js.setMsg(jsonObject.getStr("message"));
                js.setData(wechatQueryOrder);
            }
        } catch (Exception e) {
            log.error("微信支付订单查询接口调用失败,返回数据 :{}", e);
        } finally {
            try {
                Objects.requireNonNull(response).close();
            } catch (IOException e) {
                throw new GlobalException(InternationalUtils.getInternational("common.stream.close"), e.getMessage());
            }
        }
        return js;
    }

    /**
     * 4:商户订单查询
     * <p>
     * - 需要调用查询接口的情况：
     * • 当商户后台、网络、服务器等出现异常，商户系统最终未接收到支付通知。
     * • 调用支付接口后，返回系统错误或未知交易状态情况。
     * • 调用付款码支付API，返回USERPAYING的状态。
     * • 调用关单或撤销接口API之前，需确认支付状态。
     *
     * @param outTradeNo 微信支付订单号
     */
    public JSONResult queryOrderByInner(String outTradeNo) {
        WechatOrder      order;
        JSONResult       js               = new JSONResult();
        WechatQueryOrder wechatQueryOrder = new WechatQueryOrder();

        // 查询并判断是否已支付成功,支付成功直接返回,不再去查微信端
        WechatOrder wechatOrder = orderService.selectByOutTradeNo(outTradeNo);
        if (ObjectUtil.isNotEmpty(wechatOrder)
                && (StrUtil.equals(wechatOrder.getTrade_state(), CommonConstants.WECHAT_TRADE_STATE_SUCCESS)
                || StrUtil.equals(wechatOrder.getTrade_state(), CommonConstants.WECHAT_TRADE_STATE_CLOSED)
                || StrUtil.equals(wechatOrder.getTrade_state(), CommonConstants.WECHAT_TRADE_STATE_EXPIRE))
        ) {
            js.markSuccess("SUCCESS", getWechatQueryOrderFromOrder(wechatOrder));
            return js;
        }

        // 判断是否初始化wechatPayClient
        if (wechatPayClient == null) {
            setup();
        }
        // 创建 HttpClient 对象
        CloseableHttpResponse response = null;
        try {
            // 创建 HttpGet 请求
            URL     url     = new URL(CommonConstants.INNER_QUERY_ORDER_URL.concat(outTradeNo).concat("?mchid=").concat(wechatConfig.getMchId()));
            HttpGet httpGet = new HttpGet(url.toURI());
            httpGet.setHeader("Accept", "application/json");
            response = wechatPayClient.execute(httpGet);
            // 解析返回结果
            int statusCode = response.getStatusLine().getStatusCode();
            js.setStatus(statusCode);
            HttpEntity entity       = response.getEntity();
            String     responseBody = EntityUtils.toString(entity);
            if (statusCode == HttpStatus.OK.value()) {
                log.info("微信支付订单查询接口调用成功,返回数据{}", responseBody);
                // 将 JSON 字符串转换为 Java 对象
                wechatQueryOrder = JSONUtil.toBean(responseBody, WechatQueryOrder.class);
                // 金额需要从分转为元
                if (ObjectUtil.isNotEmpty(wechatQueryOrder.getAmount())) {
                    wechatQueryOrder.getAmount().setTotal(wechatQueryOrder.getAmount().getTotal() / 100);
                }
                js.setSuccess(true);
                js.setMsg("SUCCESS");
                js.setData(wechatQueryOrder);
                // 支付完成时,回调到应用系统
                order = updateOrder(wechatQueryOrder);
                WechatOrder paymentOrder = JSONUtil.toBean(responseBody, WechatOrder.class);
                if (ObjectUtil.isNotEmpty(paymentOrder) && StrUtil.equals(paymentOrder.getTrade_state(), CommonConstants.WECHAT_TRADE_STATE_SUCCESS)) {
                    PcPubCallbackUrl callbackUrl = urlService.selectByQuery(paymentOrder.getApp_flag());
                    if (ObjectUtil.isNotEmpty(callbackUrl) && StrUtil.isNotEmpty(callbackUrl.getPayResultNotifyUrl())) {
                        paymentOrder.setPay_result_notify_url(callbackUrl.getPayResultNotifyUrl());
                        boolean isSuccess = callbackToApp(HttpClient.newHttpClient(), paymentOrder);
                        order.setIs_notify(isSuccess ? 1 : 0);
                    } else {
                        log.error("通知URL不存在,无法进行回调,内部单号:{}", outTradeNo);
                    }
                }
                // 如果是待支付的订单,且已超过失效时间,将订单状态改为已关闭(微信不会更新订单为已关闭,需要自己处理,真恶心啊)
                if (StrUtil.equals(wechatQueryOrder.getTrade_state(), CommonConstants.WECHAT_TRADE_STATE_NOTPAY)) {
                    DateTimeFormatter formatter   = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX");
                    LocalDateTime     currentTime = new Date().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                    LocalDateTime     expireTime  = LocalDateTime.parse(wechatOrder.getTime_expire(), formatter);
                    if (ObjectUtil.isNotEmpty(wechatOrder) && currentTime.isAfter(expireTime)) {
                        order.setTrade_state(CommonConstants.WECHAT_TRADE_STATE_EXPIRE);
                        order.setTrade_state_desc(CommonConstants.WECHAT_TRADE_STATE_EXPIRE_DESC);
                        order.setMessage(InternationalUtils.getInternational("wechat.pay.autoClose"));
                        wechatQueryOrder.setTrade_state(CommonConstants.WECHAT_TRADE_STATE_EXPIRE);
                        wechatQueryOrder.setTrade_state_desc(CommonConstants.WECHAT_TRADE_STATE_EXPIRE_DESC);
                    }
                }
                // 更新订单信息
                orderService.updateByOutTradeNo(order);
            } else {
                log.info("微信支付订单查询接口调用失败,返回状态码 = {},返回信息 = {}", statusCode, responseBody);
                JSONObject jsonObject = JSONUtil.parseObj(responseBody);
                js.setSuccess(false);
                js.setMsg(jsonObject.getStr("message"));
                js.setData(wechatQueryOrder);
            }
        } catch (Exception e) {
            log.error("微信支付内部订单查询接口调用失败,返回数据:{}", e);
        } finally {
            try {
                Objects.requireNonNull(response).close();
            } catch (IOException e) {
                throw new GlobalException(InternationalUtils.getInternational("common.stream.close"), e.getMessage());
            }
        }
        return js;
    }

    /**
     * 5:关闭订单
     *
     * @param outTradeNo 内部订单号
     * @return
     * @throws IOException
     */
    public JSONResult closeOrder(String outTradeNo) {
        JSONResult js = new JSONResult();
        // 判断是否初始化wechatPayClient
        if (wechatPayClient == null) {
            setup();
        }
        // 封装请求参数并转成JSON
        String       reqData = "{\"mchid\":\"" + wechatConfig.getMchId() + "\"}";
        StringEntity entity  = new StringEntity(reqData, "utf-8");
        entity.setContentType("application/json");
        // 封装请求参数、完成签名并执行请求
        URL                   url      = null;
        CloseableHttpResponse response = null;
        try {
            url = new URL(CommonConstants.WECHAT_CLOSE_ORDER_URL.replace("{out_trade_no}", outTradeNo));
            HttpPost httpPost = new HttpPost(url.toURI());
            httpPost.setEntity(entity);
            httpPost.setHeader("Accept", "application/json");
            response = wechatPayClient.execute(httpPost);
        } catch (Exception e) {
            throw new GlobalException(InternationalUtils.getInternational("wechat.pay.sendFail"), e.getMessage());
        }

        try {
            // 解析返回结果
            int statusCode = response.getStatusLine().getStatusCode();
            js.setStatus(statusCode);
            if (statusCode == HttpStatus.NO_CONTENT.value()) {
                //处理成功
                log.info("关闭订单接口调用成功,返回状态码 = {},返回信息 = {}", statusCode, response);
                js.setSuccess(true);
                js.setMsg("SUCCESS");
                // 更新订单信息
                orderService.closeByOutTradeNo(outTradeNo);
            } else {
                //处理失败
                log.info("关闭订单接口调用失败,返回状态码 = {},返回信息 = {}", statusCode, response);
                js.setSuccess(false);
                js.setMsg("FAIL");
            }
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                throw new GlobalException(InternationalUtils.getInternational("common.stream.close"), e.getMessage());
            }
        }
        return js;
    }

    /**
     * 6:订单回调通知
     *
     * @return
     * @throws IOException
     */
    public JSONResult notifyOrder() {
        JSONResult        jsonResult      = new JSONResult();
        List<WechatOrder> orderPayList    = Lists.newArrayList();
        List<WechatOrder> orderExpireList = Lists.newArrayList();

        // 判断是否初始化wechatPayClient
        if (wechatPayClient == null) {
            setup();
        }

        // 查询所有待支付订单
        List<WechatOrder> list = orderService.selectNotPayOrder();
        if (list.isEmpty()) {
            log.info("操作成功,无待支付订单,无需回调,{}", list);
            return jsonResult.markFail(InternationalUtils.getInternational("wechat.pay.notCallback"), list);
        }

        // 查询所有app_flag对应的回调地址,备用
        Set<String>            appFlags = list.stream().map(WechatOrder::getApp_flag).collect(Collectors.toSet());
        List<PcPubCallbackUrl> urls     = urlService.selectListByQuery(new ArrayList<>(appFlags));

        // 轮流调接口查询订单,将结果存到集合
        List<String>       outTradeNoList  = list.stream().map(WechatOrder::getOut_trade_no).toList();
        ExecutorService    executorService = Executors.newFixedThreadPool(10); // 线程池大小可以根据实际情况调整
        List<Future<Void>> futures         = new ArrayList<>();
        long               start           = System.currentTimeMillis();
        for (String outTradeNo : outTradeNoList) {
            Future<Void> future = executorService.submit(() -> {
                try {
                    // 轮流查询订单信息,过滤出所有已支付的订单,便于后续进行回调
                    WechatQueryOrder order       = selectOrderInfo(wechatPayClient, outTradeNo);
                    WechatOrder      wechatOrder = updateOrder(order);
                    if (ObjectUtil.isNotEmpty(order) && StrUtil.equals(order.getTrade_state(), CommonConstants.WECHAT_TRADE_STATE_SUCCESS)) {
                        // 查询appFlag应用标识、回调地址
                        String appFlag     = list.stream().filter(pay -> pay.getOut_trade_no().equals(wechatOrder.getOut_trade_no())).map(WechatOrder::getApp_flag).findFirst().orElse(StrUtil.EMPTY);
                        String callbackUrl = urls.stream().filter(url -> url.getAppFlag().equals(wechatOrder.getApp_flag())).map(PcPubCallbackUrl::getPayResultNotifyUrl).findFirst().orElse(StrUtil.EMPTY);
                        wechatOrder.setApp_flag(appFlag);
                        wechatOrder.setPay_result_notify_url(callbackUrl);
                        // 添加到已支付集合,方便后续批量操作
                        orderPayList.add(wechatOrder);
                    }
                    if (ObjectUtil.isNotEmpty(order) && StrUtil.equals(order.getTrade_state(), CommonConstants.WECHAT_TRADE_STATE_NOTPAY)) {
                        // 添加到待支付集合,方便后续批量操作
                        WechatOrder orderExpire = list.stream().filter(item -> item.getOut_trade_no().equals(wechatOrder.getOut_trade_no())).findFirst().orElse(null);
                        orderExpireList.add(orderExpire);
                    }
                } catch (Exception e) {
                    log.error("微信支付通知回调接口调用失败,内部单号:{},错误信息:{}", outTradeNo, e.getMessage());
                }
                return null;
            });
            futures.add(future);
        }

        // 等待所有任务完成
        for (Future<Void> future : futures) {
            try {
                // Future.get()可以同步等待线程执行完成，并且可以监听执行结果
                future.get();
            } catch (InterruptedException | ExecutionException e) {
                log.error("任务执行异常", e);
            }
        }
        executorService.shutdown();
        log.info("定时任务核心代码耗费时间:{}ms", System.currentTimeMillis() - start);

        // 待支付集合中存在超时订单,则更新为已关闭
        DateTimeFormatter formatter   = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX");
        LocalDateTime     currentTime = new Date().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        if (!orderExpireList.isEmpty()) {
            for (WechatOrder item : orderExpireList) {
                LocalDateTime expireTime = LocalDateTime.parse(item.getTime_expire(), formatter);
                if (ObjectUtil.isNotEmpty(item) && currentTime.isAfter(expireTime)) {
                    item.setTrade_state(CommonConstants.WECHAT_TRADE_STATE_EXPIRE);
                    item.setTrade_state_desc(CommonConstants.WECHAT_TRADE_STATE_EXPIRE_DESC);
                    item.setMessage(InternationalUtils.getInternational("wechat.pay.autoClose"));
                }
            }
            // 批量更新已超时未支付的订单
            orderService.batchUpdateByOutTradeNo(orderExpireList);
        }

        if (orderPayList.isEmpty()) {
            log.info("操作成功,所有订单均未支付,无需回调,{}", list);
            return jsonResult.markFail("操作成功,所有订单均未支付,无需回调", list);
        }

        List<WechatOrder> existUrlList    = orderPayList.stream().filter(order -> StrUtil.isNotEmpty(order.getPay_result_notify_url())).toList();
        List<WechatOrder> notExistUrlList = orderPayList.stream().filter(order -> StrUtil.isEmpty(order.getPay_result_notify_url())).toList();
        log.error("需要进行回调的部分(通知URL存在):{},无法进行回调的部分(通知URL不存在):{}", existUrlList, notExistUrlList);
        // 已支付的部分:根据回调地址,通知到各个应用
        HttpClient httpClient = HttpClient.newHttpClient();
        for (WechatOrder paymentOrder : existUrlList) {
            boolean isSuccess = callbackToApp(httpClient, paymentOrder);
            orderPayList.forEach(order -> {
                if (StrUtil.equals(order.getOut_trade_no(), paymentOrder.getOut_trade_no())) {
                    order.setIs_notify(isSuccess ? 1 : 0);
                }
            });
        }
        // 批量更新已支付订单信息(包含上一步骤中,通知各应用的回调结果)
        orderService.batchUpdateByOutTradeNo(orderPayList);
        log.info("操作成功,已回调各应用,{}", existUrlList);
        return jsonResult.markFail(InternationalUtils.getInternational("wechat.pay.success"), existUrlList);
    }

    /**
     * 7:订单退款(支持部分退款,有并发风险)
     *
     * @return
     * @throws IOException
     */
    public JSONResult refund(WechatRefundParam param) {
        JSONResult js = new JSONResult();
        // 查询并判断,订单不是支付已完成或转入退款状态则直接返回,不再去查微信端
        WechatOrder               wechatOrder;
        List<WechatRefundHistory> historyList;
        double                    addRefundTotal = 0;
        if (StrUtil.isNotEmpty(param.getOutTradeNo())) {
            wechatOrder = orderService.selectByOutTradeNo(param.getOutTradeNo());
        } else {
            wechatOrder = orderService.selectByTransactionId(param.getTransactionId());
        }
        // 判断订单是否存在
        if (ObjectUtil.isEmpty(wechatOrder)) {
            return js.markFail("订单不存在");
        }
        if (ObjectUtil.isNotEmpty(wechatOrder) && !StrUtil.equals(wechatOrder.getTrade_state(), CommonConstants.WECHAT_TRADE_STATE_SUCCESS)) {
            return js.markFail("当前订单未支付,无法进行退款");
        }
        // 判断退款总金额和订单金额
        if (StrUtil.isNotEmpty(param.getOutTradeNo())) {
            historyList = refundHistoryService.selectListByOutTradeNo(param.getOutTradeNo());
        } else {
            historyList = refundHistoryService.selectListByTransactionId(param.getTransactionId());
        }
        if (CollectionUtil.isNotEmpty(historyList)) {
            addRefundTotal = historyList.stream().mapToDouble(WechatRefundHistory::getRefund).sum();
        }
        double sumRefund = param.getRefund() + addRefundTotal;
        if (sumRefund > wechatOrder.getTotal()) {
            return js.markFail("累积退款金额不能大于订单总金额");
        }
        // 判断是否初始化wechatPayClient
        if (wechatPayClient == null) {
            setup();
        }
        // 封装请求参数并转成JSON
        WechatRefund wechatRefund = new WechatRefund(
                wechatOrder.getTransaction_id(),
                wechatOrder.getOut_trade_no(),
                param.getOutRefundNo(),
                param.getReason(),
                wechatConfig.getWechatRefundNotifyUrl(),
                CommonConstants.WECHAT_FUNDS_ACCOUNT,
                param.getRefund() * 100,
                wechatOrder.getTotal() * 100
        );
        String       reqData = JSONUtil.toJsonStr(wechatRefund);
        StringEntity entity  = new StringEntity(reqData, "utf-8");
        entity.setContentType("application/json");
        // 封装请求参数、完成签名并执行请求
        HttpPost httpPost = new HttpPost(CommonConstants.WECHAT_REFUND_URL);
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");

        CloseableHttpResponse response = null;
        try {
            response = wechatPayClient.execute(httpPost);
            // 解析返回结果
            int        statusCode   = response.getStatusLine().getStatusCode();
            HttpEntity httpEntity   = response.getEntity();
            String     responseBody = EntityUtils.toString(httpEntity);
            if (statusCode == HttpStatus.OK.value()) {
                // 处理成功
                log.info("退款接口调用成功,返回状态码 = {},返回信息 = {}", statusCode, responseBody);
                WechatRefundResult wechatRefundResult = JSONUtil.toBean(responseBody, WechatRefundResult.class);
                // 金额需要从分转为元
                if (ObjectUtil.isNotEmpty(wechatRefundResult.getAmount())) {
                    wechatRefundResult.getAmount().setTotal(wechatRefundResult.getAmount().getTotal() / 100);
                    wechatRefundResult.getAmount().setRefund(wechatRefundResult.getAmount().getRefund() / 100);
                    wechatRefundResult.getAmount().setRefund_fee(wechatRefundResult.getAmount().getRefund_fee() / 100);
                    wechatRefundResult.getAmount().setPayer_total(wechatRefundResult.getAmount().getPayer_total() / 100);
                    wechatRefundResult.getAmount().setPayer_refund(wechatRefundResult.getAmount().getPayer_refund() / 100);
                    wechatRefundResult.getAmount().setSettlement_refund(wechatRefundResult.getAmount().getSettlement_refund() / 100);
                    wechatRefundResult.getAmount().setSettlement_total(wechatRefundResult.getAmount().getSettlement_total() / 100);
                    wechatRefundResult.getAmount().setDiscount_refund(wechatRefundResult.getAmount().getDiscount_refund() / 100);
                }
                js.markSuccess("SUCCESS", wechatRefundResult);
                // 存到退款日志表
                refundHistoryService.save(getWechatRefundHistory(wechatRefundResult));
            } else {
                // 处理失败
                log.info("退款接口调用失败,返回状态码 = {},返回信息 = {}", statusCode, response);
                JSONObject jsonObject = JSONUtil.parseObj(responseBody);
                js.markFail(jsonObject.getStr("message"));
            }
        } catch (Exception e) {
            throw new GlobalException(InternationalUtils.getInternational("wechat.refund.sendFail"), e.getMessage());
        } finally {
            try {
                Objects.requireNonNull(response).close();
            } catch (IOException e) {
                throw new GlobalException(InternationalUtils.getInternational("common.stream.close"), e.getMessage());
            }
        }
        return js;
    }

    /**
     * 8:退款通知回调
     *
     * @return
     * @throws IOException
     */
    public WechatCallbackResult refundCallback(HttpServletRequest request, HttpServletResponse response) {
        // 判断是否初始化验签配置
        if (verifier == null) {
            setupForVerifier();
        }
        // 获取报文及相关请求头信息
        String body = getRequestBody(request);
        log.info("收到微信退款回调,返回数据：{}", body);
        String nonceStr  = request.getHeader("Wechatpay-Nonce");
        String signature = request.getHeader("Wechatpay-Signature");
        String serialNo  = request.getHeader("Wechatpay-Serial");
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        //构造签名串
        String               signStr              = Stream.of(timestamp, nonceStr, body).collect(Collectors.joining("\n", "", "\n"));
        WechatCallbackResult wechatCallbackResult = new WechatCallbackResult(CommonConstants.RESULT_SUCCESS, CommonConstants.RESULT_SUCCESS_MSG);
        try {
            //验证签名是否通过
            boolean result = verifiedSign(serialNo, signStr, signature);
            if (result) {
                //解密数据
                String plainBody = decryptBody(body);
                log.info("解密后的退款回调明文:{}", plainBody);
                JSONObject jsonObject   = JSONUtil.parseObj(plainBody);
                String     refundStatus = jsonObject.getStr("refund_status");
                String     outRefundNo  = jsonObject.getStr("out_refund_no");

                //退款完成时,回调到应用系统
                /*if(StrUtil.equals(refundStatus,CommonConstant.WECHAT_REFUND_STATE_SUCCESS)){
                    String payResultNotifyUrl = urlService.selectByOutTradeNo(wechatRefundResult.getOut_trade_no());
                    if (StrUtil.isNotEmpty(payResultNotifyUrl)) {
                        log.error("通知URL存存在,退款开始回调,内部退款单号:{}", outRefundNo);
                    } else {
                        log.error("通知URL不存在,无法进行回调,内部退款单号:{}", outRefundNo);
                    }
                }*/

                // 更新退款订单状态
                refundHistoryService.updateState(new WechatRefundHistory(outRefundNo, refundStatus, new Date()));
            }
        } catch (Exception e) {
            log.error("微信退款回调异常:{}", e);
            wechatCallbackResult = new WechatCallbackResult(CommonConstants.RESULT_FAIL, CommonConstants.RESULT_FAIL_MSG);
        }
        return wechatCallbackResult;
    }

    /**
     * 9:内部/商户退款单号查询退款接口
     *
     * @param outRefundNo 微信退款订单号
     */
    public JSONResult queryRefund(String outRefundNo){
        JSONResult         js = new JSONResult();
        WechatRefundResult wechatRefundResult;

        // 查询退款记录表,并判断是否已退款成功,退款成功直接返回,不再去查微信端
        /*WechatRefundHistory wechatRefundHistory = refundHistoryService.selectByOutRefundNo(outRefundNo);
        if (ObjectUtil.isNotEmpty(wechatRefundHistory) && StrUtil.equals(wechatRefundHistory.getRefund_status(), CommonConstant.WECHAT_REFUND_STATE_SUCCESS)) {
            return js.markSuccess("SUCCESS", getWechatRefundResultFromHist(wechatRefundHistory));
        }*/

        // 判断是否初始化wechatPayClient
        if (wechatPayClient == null) {
            setup();
        }
        CloseableHttpResponse response = null;
        try {
            // 创建 HttpGet 请求
            URL     url     = new URL(CommonConstants.WECHAT_REFUND_QUERY_URL.replace("{out_refund_no}", outRefundNo));
            HttpGet httpGet = new HttpGet(url.toURI());
            httpGet.setHeader("Accept", "application/json");

            // 发送 GET 请求并获取响应
            response = wechatPayClient.execute(httpGet);
            // 解析返回结果
            int        statusCode   = response.getStatusLine().getStatusCode();
            HttpEntity entity       = response.getEntity();
            String     responseBody = EntityUtils.toString(entity);
            JSONObject jsonObject   = JSONUtil.parseObj(responseBody);
            if (statusCode == HttpStatus.OK.value()) {
                log.info("微信退款查询接口调用成功,返回数据{}", responseBody);
                // 将 JSON 字符串转换为 Java 对象
                wechatRefundResult = JSONUtil.toBean(responseBody, WechatRefundResult.class);
                // 金额需要从分转为元
                if (ObjectUtil.isNotEmpty(wechatRefundResult.getAmount())) {
                    wechatRefundResult.getAmount().setTotal(wechatRefundResult.getAmount().getTotal() / 100);
                    wechatRefundResult.getAmount().setRefund(wechatRefundResult.getAmount().getRefund() / 100);
                    wechatRefundResult.getAmount().setRefund_fee(wechatRefundResult.getAmount().getRefund_fee() / 100);
                    wechatRefundResult.getAmount().setPayer_total(wechatRefundResult.getAmount().getPayer_total() / 100);
                    wechatRefundResult.getAmount().setPayer_refund(wechatRefundResult.getAmount().getPayer_refund() / 100);
                    wechatRefundResult.getAmount().setSettlement_refund(wechatRefundResult.getAmount().getSettlement_refund() / 100);
                    wechatRefundResult.getAmount().setSettlement_total(wechatRefundResult.getAmount().getSettlement_total() / 100);
                    wechatRefundResult.getAmount().setDiscount_refund(wechatRefundResult.getAmount().getDiscount_refund() / 100);
                }
                js.markSuccess("SUCCESS", wechatRefundResult);

                // 退款完成时,回调到应用系统
                /*if(StrUtil.equals(wechatRefundResult.getRefund_status(),CommonConstant.WECHAT_REFUND_STATE_SUCCESS)){
                    String payResultNotifyUrl = urlService.selectByOutTradeNo(wechatRefundResult.getOut_trade_no());
                    if (StrUtil.isNotEmpty(payResultNotifyUrl)) {
                        log.error("通知URL存存在,退款开始回调,内部退款单号:{}", outRefundNo);
                    } else {
                        log.error("通知URL不存在,无法进行回调,内部退款单号:{}", outRefundNo);
                    }
                }*/

                // 更新退款订单状态
                wechatRefundResult.setRefund_status(jsonObject.getStr("status"));
                refundHistoryService.updateState(getWechatRefundHistory(wechatRefundResult));
            } else {
                log.info("微信退款订单查询接口调用失败,返回状态码 = {},返回信息 = {}", statusCode, responseBody);
                js.markFail(jsonObject.getStr("message"));
            }
        } catch (Exception e) {
            log.error("微信退款内部订单查询接口调用失败,返回数据:{}", e);
            throw new GlobalException(InternationalUtils.getInternational("wechat.refund.queryFail"), e.getMessage());
        } finally {
            try {
                Objects.requireNonNull(response).close();
            } catch (IOException e) {
                throw new GlobalException(InternationalUtils.getInternational("common.stream.close"), e.getMessage());
            }
        }
        return js;
    }

    /**
     * 查询订单信息的方法
     *
     * @param client
     * @param outTradeNo
     * @return
     * @throws IOException
     * @throws URISyntaxException
     */
    private WechatQueryOrder selectOrderInfo(CloseableHttpClient client, String outTradeNo) {
        // 创建 HttpGet 请求
        URL     url     = null;
        HttpGet httpGet = null;
        try {
            url = new URL(CommonConstants.INNER_QUERY_ORDER_URL.concat(outTradeNo).concat("?mchid=").concat(wechatConfig.getMchId()));
            httpGet = new HttpGet(url.toURI());
        } catch (MalformedURLException | URISyntaxException e) {
            throw new GlobalException(InternationalUtils.getInternational("wechat.pay.urlParseFail"), e.getMessage());
        }
        httpGet.setHeader("Accept", "application/json");
        // 发送 GET 请求并获取响应
        WechatQueryOrder wechatQueryOrder = null;
        try (CloseableHttpResponse response = client.execute(httpGet)) {
            // 解析返回结果
            int        statusCode   = response.getStatusLine().getStatusCode();
            HttpEntity entity       = response.getEntity();
            String     responseBody = EntityUtils.toString(entity, "UTF-8");
            if (statusCode == HttpStatus.OK.value()) {
                log.info("微信支付订单查询接口调用成功(通知),返回数据{}", responseBody);
                // 将 JSON 字符串转换为 Java 对象
                wechatQueryOrder = JSONUtil.toBean(responseBody, WechatQueryOrder.class);
                // 金额需要从分转为元
                if (ObjectUtil.isNotEmpty(wechatQueryOrder.getAmount())) {
                    wechatQueryOrder.getAmount().setTotal(wechatQueryOrder.getAmount().getTotal() / 100);
                }
            } else {
                log.info("微信支付订单查询接口调用失败(通知),返回状态码 = {},返回信息 = {}", statusCode, responseBody);
            }
        } catch (IOException e) {
            throw new GlobalException(InternationalUtils.getInternational("wechat.pay.dataParseFail"), e.getMessage());
        }
        return wechatQueryOrder;
    }

    /**
     * 回调应用方的方法
     *
     * @param httpClient
     * @param currentOrder
     */
    private boolean callbackToApp(HttpClient httpClient, WechatOrder currentOrder) {
        boolean           isSuccess         = false;
        WechatPayCallback wechatPayCallback = BeanUtil.copyProperties(currentOrder, WechatPayCallback.class);
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(currentOrder.getPay_result_notify_url()))
                .header("Content-Type", "application/json") // 设置 Content-Type 为 application/json
                .POST(HttpRequest.BodyPublishers.ofString(JSONUtil.toJsonStr(wechatPayCallback), StandardCharsets.UTF_8)) // 设置 POST 请求体
                .build();
        try {
            HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
            isSuccess = JSONUtil.parseObj(response.body()).getBool("isSuccess");
        } catch (Exception e) {
            log.error("微信支付结果回调应用系统失败,内部订单号:{},数据:{},错误信息:{}", wechatPayCallback.getOut_trade_no(), wechatPayCallback, e.getMessage());
        }
        return isSuccess;
    }

    /**
     * 获取订单过期时间
     *
     * @return
     */
    private String getExpireTime() {
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        // 加 失效时间 (默认15分钟,可以在配置文件中的wechat.expireMinutes属性进行设置)
        LocalDateTime fifteenMinutesLater = now.plusMinutes(wechatConfig.getExpireMinutes());
        // 定义格式化器
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX");
        // 格式化时间
        return fifteenMinutesLater.atZone(ZoneId.systemDefault()).format(formatter);
    }

}
